#ifndef HETMANSPROBLEM_H
#define HETMANSPROBLEM_H

#include <boost/math/special_functions/factorials.hpp>
#include <vector>
#include "Problem.h"

/**
 * Klasa HetmansProblem opisuje problem N Hetmanów
 *
 * Szachownica NxN. Aktualny stan problemu to wektor N (liczb state_).
 * i-ta liczba oznacza pozycję hetmana z i-tej kolumny na szachownicy.
 * W każdym kroku możliwych jest N * (N - 1) stanów następnych. Każdy z tych
 * stanów reprezentuje przesunięcie któregoś hetmana wzdłuż kolumny szachownicy,
 * w której się znajduje.
 * Stany-następniki identyfikowane są liczbą całkowitą. Liczba ta to numer pola
 * na szachownicy.
 *
 * Przykład: Jeśli stan-następnik to S, wówczas hetman, którego trzeba przesunąć,
 * aby przejść do tego stanu znajduje się w kolumnie S / N (dzielenie całkowite),
 * zaś pole, na które trzeba go przesunąć to S % N (dzielenie modulo).
 */
class HetmansProblem : public Problem {

    const int N;        // szachownica NxN
    const int MAX_WEIGHT;

    std::vector<int> state_;
    std::vector<int> nextStates_;
    float currentWeight_;

private:
    void calculateCurrentEnergy();
    float calculateWeight ( const std::vector<int> & state ) const;
    float weight ( int state ) const;

public:
    /**
     * @param n bok szachownicy
     */
    HetmansProblem ( int n );

    /**
     * @param start_state stan początkowy
     */
    HetmansProblem ( const std::vector<int> & start_state );

    /**
     * Liczy energię dla podanego stanu.
     * @param state stan, dla którego ma być policzona energia układu.
     */
    float energy ( int state ) const;

    /**
     * Liczy energię dla aktualnego stanu.
     */
    float currentEnergy() const;

    /**
     * Przechodzi we wskazany stan
     * @param state stan.
     */
    void setState ( int state );

    /**
     * Generuje stany-następniki.
     * @param container wektor, do którego mają być włożone stany-następniki
     */
    void generateStates ( std::vector< int >& container );

    /**
     * @return czy problem w aktualnym stanie jest rozwiązany
     */
    bool isSolved() const;
    virtual ~HetmansProblem();

private:
    inline int combination ( int value ) const {
        return boost::math::factorial<double> ( value ) / ( 2 * boost::math::factorial<double> ( value - 2 ) );
    }
};

#endif // HETMANSPROBLEM_H
